package com.syh.jn.scm.domain.supplier.entity.sale;

import cn.redscarf.commons.spring.SpringContextUtils;
import cn.redscarf.commons.util.bean.ExtBeanUtils;
import cn.redscarf.commons.util.other.ExtAssert;
import cn.redscarf.commons.util.validator.ValidationUtils;
import cn.redscarf.commons.wrapper.Restrictions;
import cn.redscarf.commons.wrapper.Wrapper;
import com.syh.core.ddd.domain.AbstractSimpleAggregate;
import com.syh.core.ddd.domain.CodeExpEnum;
import com.syh.core.ddd.domain.CodeGenerateUtil;
import com.syh.jn.scm.domain.supplier.entity.logistics.LogisticsBill;
import com.syh.jn.scm.domain.supplier.repository.logistics.LogisticsBillReadRepository;
import com.syh.jn.scm.dto.supplier.sale.SaleReturnOrderMto;
import com.syh.jn.scm.dto.supplier.sale.SaleReturnOrderSto;
import com.syh.jn.scm.dto.support.FilesDto;
import com.syh.jn.scm.exception.BusinessException;
import com.syh.jn.scm.service.api.supplier.logistics.enums.LogisticsBillEnums;
import com.syh.jn.scm.service.api.supplier.sale.enums.SaleReturnOrderEnums;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.NoArgsConstructor;

import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.List;

/**
 * 销售退货单聚合
 */
@Data
@NoArgsConstructor
@EqualsAndHashCode(callSuper = true)
public class SaleReturnOrder extends AbstractSimpleAggregate<Long> {
  public SaleReturnOrder(Long id) {
    this.id = id;
  }

  public static SaleReturnOrder createBySupply(SaleReturnOrderSto sto) {
    ExtAssert.notNull(sto, "销售退货单STO为空");
    ValidationUtils.validate(sto);
    //由服务商创建订单的创建状态为0
    SaleReturnOrder order = commonCreateSaleReturnOrder(Short.valueOf("0"));
    order.setCode(CodeGenerateUtil.codeGenerate(CodeExpEnum.SALES_RETURN_ORDER_EXP.getCodeExp(), sto.getDownStreamCompanyId()));
    ExtBeanUtils.copyProperties(sto, order);
    //添加订单项
    ExtAssert.notNull(sto.getItems(), "销售退货单商品列表为空");
    order.items = new ArrayList<>();
    sto.getItems().stream().forEach(item -> {
      ValidationUtils.validate(item);
      order.addItem(new SaleReturnOrderItem(item));
    });
    //计算订单总额
    order.calculateTotalAmount();

    return order;
  }

  //计算订单总额和商品总额的方法
  private void calculateTotalAmount() {
    BigDecimal totalAmount = BigDecimal.ZERO;
    for (SaleReturnOrderItem item : this.items) {
      totalAmount = totalAmount.add(item.getReturnTotalAmount());
    }
    this.returnTotalGoodsAmount = totalAmount;//退货订单商品总额
    //减去优惠价格
    if (this.discount != null) {
      totalAmount = totalAmount.subtract(this.discount);
    }
    //退货订单总额
    this.returnTotalAmount = totalAmount;
  }

  //计算入库订单总额和入库商品总额的方法
  private void calculateTotalReturnInAmount() {
    //计算销售退货订单入库商品总额
    BigDecimal totalAmount = BigDecimal.ZERO;
    for (SaleReturnOrderItem item : this.items) {
      totalAmount = totalAmount.add(item.calculateTotalReturnInAmount());
    }
    this.returnTotalInGoodsAmount = totalAmount;

    //先计算出该订单下已签收状态的物流单据的物流费用
    LogisticsBillReadRepository logisticsBillReadRepository = (LogisticsBillReadRepository) SpringContextUtils.getBean(LogisticsBillReadRepository.class);
    Wrapper we = Wrapper.build();
    we.append(Restrictions.eq("orderId", this.id));
    we.append(Restrictions.eq("orderType", LogisticsBillEnums.OrderType.RETURN_SALE.getStatus()));
    we.append(Restrictions.eq("logisticsState", LogisticsBillEnums.State.SIGNIN.getStatus()));
    List<LogisticsBill> logisticsBills = logisticsBillReadRepository.getList(we);

    BigDecimal logisticsBillBeforeBuyFreight = BigDecimal.ZERO;//物流单据为预收买家的所有物流费用
    for (LogisticsBill logisticsBill : logisticsBills) {
      boolean justDo = logisticsBill.getFreightTake() != null &&
              logisticsBill.getFreightTake().equals(LogisticsBillEnums.FreightTake.BUY.getStatus())
              && logisticsBill.getFreightType().equals(LogisticsBillEnums.FreightType.BEFORE.getStatus());
      if (justDo) {
        logisticsBillBeforeBuyFreight = logisticsBillBeforeBuyFreight.add(logisticsBill.getTotalFreight());
      }
    }

    //计算销售退货订单入库总额
    //减去优惠价格
    if (this.discount != null) {
      totalAmount = totalAmount.subtract(this.discount);
    }
    totalAmount = totalAmount.add(logisticsBillBeforeBuyFreight);
    this.returnTotalInAmount = totalAmount.compareTo(BigDecimal.ZERO) < 1 ? BigDecimal.ZERO : totalAmount;
    this.lastUpdateTimeStamp = System.currentTimeMillis();
  }

  //计算入库订单状态
  private void calculateCollectStatus() {
    //默认为已完全签收
    this.collectState = SaleReturnOrderEnums.CollectState.LOGISTICS_WHOLE_COLLECT.getStatus();
    //默认标记为未生成物流单
    boolean unCollected = true;

    for (SaleReturnOrderItem item : this.items) {
      //订单项已生成数量小于订单数量则为部分生成物流单
      if (this.collectState.equals(SaleReturnOrderEnums.CollectState.LOGISTICS_WHOLE_COLLECT.getStatus())
              && item.getReturnInQuantity().compareTo(item.getReturnQuantity()) < 0) {
        this.collectState = SaleReturnOrderEnums.CollectState.LOGISTICS_PART_COLLECT.getStatus();
      }
      //订单项已发货数量大于0 则不是未发货
      if (unCollected && item.getReturnInQuantity().compareTo(BigDecimal.ZERO) > 0) {
        unCollected = false;
      }
    }
    if (unCollected) {
      this.collectState = SaleReturnOrderEnums.CollectState.LOGISTICS_UN_COLLECT.getStatus();
      this.depotTimestamp = null;
    }
  }

  /**
   * SaleReturnOrderService
   * 设置初始的参数
   *
   * @param createdType
   * @return
   */
  public static SaleReturnOrder commonCreateSaleReturnOrder(Short createdType) {
    SaleReturnOrder order = new SaleReturnOrder();
    order.returnOrdState = SaleReturnOrderEnums.State.STAYCONFIRM.getStatus();
    order.generatedState = SaleReturnOrderEnums.GeneratedState.LOGISTICS_UN_GENERATE.getGeneratedState();
    order.deliveryState = SaleReturnOrderEnums.DeliveryState.LOGISTICS_UN_DELIVERY.getStatus();
    order.collectState = SaleReturnOrderEnums.CollectState.LOGISTICS_UN_COLLECT.getStatus();
    order.createType = createdType;
    order.totalFreight = BigDecimal.ZERO;
    order.discount = BigDecimal.ZERO;//设置优惠金额的默认金额为0
    order.createTimeStamp = System.currentTimeMillis();
    return order;
  }

  /**
   * 增加订单项
   *
   * @param item
   * @return
   */
  public SaleReturnOrder addItem(SaleReturnOrderItem item) {
    if (this.items == null) {
      this.items = new ArrayList<>();
    }
    this.items.add(item);
    return this;
  }

  /**
   * 供应商修改销售退货单
   */
  public void modify(SaleReturnOrderMto mto) {
    ExtAssert.notNull(mto, "销售退货单MTO对象为空");
    ValidationUtils.validate(mto);
    if (!this.getReturnOrdState().equals(Short.valueOf("0"))) {
      throw new BusinessException("订单不是待确认状态,不可以修改");
    }
    ExtBeanUtils.copyProperties(mto, this, false);
    this.lastUpdateTimeStamp = System.currentTimeMillis();
    this.items = new ArrayList<>();
    mto.getItems().stream().forEach(item -> {
      ValidationUtils.validate(item);
      //验证退货数量
      this.addItem(new SaleReturnOrderItem(item));
    });
    this.calculateTotalAmount();
  }

  /**
   * 删除订单，先判断订单状态再删除订单项
   */
  public void destory() {
    if (!this.returnOrdState.equals(SaleReturnOrderEnums.State.CANCEL.getStatus())) {
      throw new BusinessException("订单不是已取消状态,不可以删除");
    }
    if (this.haveRecord != null &&
            this.haveRecord.equals(SaleReturnOrderEnums.State.HAVE_RECORD.getStatus())) {
      throw new BusinessException("订单已存在记录,不可以删除");
    }
  }

  /**
   * 删除订单项方法
   *
   * @param item
   * @return
   */
  public SaleReturnOrder removeItem(SaleReturnOrderItem item) {
    this.items.removeIf((innerItem) -> {
      return innerItem.getId().equals(item.getId());
    });
    return this;
  }

  /**
   * 确认订单方法
   */
  public void confirm() {
    if (!this.getReturnOrdState().equals(SaleReturnOrderEnums.State.STAYCONFIRM.getStatus())) {
      throw new BusinessException("订单不是待确认状态,不可以确认");
    }
    this.returnOrdState = SaleReturnOrderEnums.State.CONFIRM.getStatus();
  }

  /**
   * 取消订单方法
   */
  public void cancel() {
    if (!this.getReturnOrdState().equals(SaleReturnOrderEnums.State.STAYCONFIRM.getStatus())) {
      throw new BusinessException("订单不是待确认状态,不可以取消");
    }
    this.returnOrdState = SaleReturnOrderEnums.State.CANCEL.getStatus();
  }

  /**
   * 取消确认订单
   */
  public void cancelConfirm() {
    if (!this.getReturnOrdState().equals(SaleReturnOrderEnums.State.CONFIRM.getStatus())) {
      throw new BusinessException("订单不是确认状态,不可以取消确认");
    }
    LogisticsBillReadRepository logisticsBillReadRepository = (LogisticsBillReadRepository) SpringContextUtils.getBean(LogisticsBillReadRepository.class);
    Wrapper we = Wrapper.build().append(Restrictions.eq("orderId", this.id))
            .append(Restrictions.eq("orderType", LogisticsBillEnums.OrderType.RETURN_SALE.getStatus()));
    if (logisticsBillReadRepository.getCount(we) > 0) {
      throw new BusinessException("订单已生成物流单,不可以取消确认");
    }
    this.returnOrdState = SaleReturnOrderEnums.State.STAYCONFIRM.getStatus();
  }

  /**
   * 更新收货信息
   */
  public void collect(LogisticsBill bill) {
    if (this.collectState.equals(SaleReturnOrderEnums.CollectState.LOGISTICS_WHOLE_COLLECT.getStatus())) {
      throw new BusinessException("签收失败，已全部签收！");
    }

    //获取物流单据明细并计算订单项的已收货数量
    bill.getItems().forEach(logisticsBillItem -> {
      this.items.forEach(orderItem -> {
        if (orderItem.getId().equals(logisticsBillItem.getOrderItemId())) {
          orderItem.setReturnInQuantity(orderItem.getReturnInQuantity() == null ? logisticsBillItem.getQuantity() :
                  orderItem.getReturnInQuantity().add(logisticsBillItem.getQuantity()));
        }
      });
    });
    this.haveRecord = SaleReturnOrderEnums.State.HAVE_RECORD.getStatus();
    this.depotTimestamp = System.currentTimeMillis();
    this.calculateTotalReturnInAmount();
    this.calculateCollectStatus();
  }

  /**
   * 更新取消收货信息
   */
  public void cancelCollect(LogisticsBill bill) {
    if (this.collectState.equals(SaleReturnOrderEnums.CollectState.LOGISTICS_UN_COLLECT.getStatus())) {
      throw new BusinessException("取消签收失败，无签收记录！");
    }

    //获取物流单据明细并计算订单项的已收货数量
    bill.getItems().forEach(logisticsBillItem -> {
      this.items.forEach(orderItem -> {
        if (orderItem.getId().equals(logisticsBillItem.getOrderItemId())) {
          orderItem.setReturnInQuantity(orderItem.getReturnInQuantity().subtract(logisticsBillItem.getQuantity()));
        }
      });
    });
    this.calculateTotalReturnInAmount();
    this.calculateCollectStatus();
  }

  /**
   * 生成对账单
   */
  public void generating(Long statementOfAccountId) {
    if (this.collectState.equals(SaleReturnOrderEnums.CollectState.LOGISTICS_UN_COLLECT.getStatus())) {
      throw new BusinessException("销售退货单" + this.code + "未签收，无法生成对账单");
    }
    if (this.returnOrdState.equals(SaleReturnOrderEnums.State.STATEMENT.getStatus())) {
      throw new BusinessException("销售退货单已生成对账单!");
    }
    this.statementId = statementOfAccountId;
    this.returnOrdState = SaleReturnOrderEnums.State.STATEMENT.getStatus();
  }

  /**
   * 取消对账单
   */
  public void cancelGenerating() {
    if (this.returnOrdState.equals(SaleReturnOrderEnums.State.CONFIRM.getStatus())) {
      throw new BusinessException("销售退货单已取消对账单!");
    }
    this.statementId = null;
    this.returnOrdState = SaleReturnOrderEnums.State.CONFIRM.getStatus();
  }

  /**
   * 销售退货订单上传图片
   *
   * @param dto
   */
  public void upload(FilesDto dto) {
    this.mainSrcImages = dto.getFiles();
  }

  /**
   * 销售退货单编号
   */
  private String code;
  /**
   * 第三方订单号
   */
  private String extCode;
  /**
   * 对应销售单id
   */
  private Long saleOrderId;
  /**
   * 归属id
   */
  private Long businessEntityId;
  /**
   * 对应对账单id
   */
  private Long statementId;
  /**
   * 退货单状态(0：待确认 1：已确认 2：挂起 3：已生成对账单 -1：已取消)
   */
  private Short returnOrdState;
  /**
   * 发货状态(0：未发货 1：部分发货 2：完成发货)
   */
  private Short deliveryState;
  /**
   * 签收状态(0：未签收 1：部分签收 2：完成签收)
   */
  private Short collectState;
  /**
   * 物流生成状态(0：未生成物流单 1：部分生成物流单2：完成生成物流单)
   */
  private Short generatedState;
  /**
   * 订单创建类型(字典获取 fixed 0：服务商录入 1:客户录入 2：对接客户系统 3：系统自动)
   */
  private Short createType;
  /**
   * 下游购买单位ID
   */
  private Long downStreamCompanyId;
  /**
   * 备注
   */
  private String remark;
  /**
   * 订单总额
   */
  private BigDecimal totalAmount;
  /**
   * 退货订单总额
   */
  private BigDecimal returnTotalAmount;
  /**
   * 退货订单商品总额
   */
  private BigDecimal returnTotalGoodsAmount;
  /**
   * 退货出库总额
   */
  private BigDecimal returnTotalOutAmount;
  /**
   * 退货出库商品总额
   */
  private BigDecimal returnTotalOutGoodsAmount;
  /**
   * 退货签收总额
   */
  private BigDecimal returnTotalInAmount;
  /**
   * 退货签收商品总额
   */
  private BigDecimal returnTotalInGoodsAmount;
  /**
   * 运费金额
   */
  private BigDecimal totalFreight;
  /**
   * 优惠金额
   */
  private BigDecimal discount;
  /**
   * 录入日期
   */
  private Long inputDateTimestamp;
  /**
   * 发货时间
   */
  private Long deliveryTimestamp;
  /**
   * 预计到达时间
   */
  private Long etaDateTimestamp;
  /**
   * 录单人ID
   */
  private Long operatorId;
  /**
   * 收货人姓名
   */
  private String deliName;
  /**
   * 收货人联系电话
   */
  private String deliTel;
  /**
   * 收货地区编码
   */
  private String deliAreaCode;
  /**
   * 收货地址省市区
   */
  private String deliArea;
  /**
   * 收货人详细地址
   */
  private String deliAddress;
  /**
   * 退货原因id
   */
  private Long returnReasonId;
  /**
   * 退货入库时间
   */
  private Long depotTimestamp;
  /**
   * 发货省市区
   */
  private String postArea;
  /**
   * 发货详细地址
   */
  private String postAddress;
  /**
   * 我方单据图片
   */
  private String mainSrcImages;
  /**
   * 对方单据图片
   */
  private String secondSrcImages;
  /**
   * 是否已生成记录(库存记录、应收付记录等) 0:未生成 1：已生成
   */
  private Short haveRecord;
  /**
   * 销售退货订单明细
   */
  private List<SaleReturnOrderItem> items;
}
